#ifndef __LOGGER_STREAM_HPP__
#define __LOGGER_STREAM_HPP__

#include <sstream>
#include <cstring>

namespace utils {

	static const char nl = '\n';

class logger_stream {
	public:
		class multi_line {
			protected:
				mutable std::stringstream _data;
				mutable std::stringstream& data;

				multi_line(const multi_line& other);
			public:
				multi_line(const std::string& lines) : _data(lines), data(_data) {
				}

				multi_line(std::stringstream& iss) : data(iss) {
				}

				void set(const std::string& lines) {
					_data.clear();
					_data.str(lines);
				}

				std::stringstream& getStream() const {
					return data;
				}		
		}; // class multi_line

	protected:
		FILE* fp;
		std::ostringstream buffer;
//		std::ostream& sink;
		char sep;
		std::string color;
		
//		logger_stream(const logger_stream& ls);
//		logger_stream& operator= (const logger_stream& ls);

		virtual void make_header(std::ostringstream& header) {
			static struct tm* timeinfo;
			static struct timeval utime;
			static char strTime[11];

			gettimeofday(&utime,NULL);
			timeinfo = localtime((&utime.tv_sec));
			strftime(strTime, 20,"%Y/%m/%d", timeinfo);
//			strTime[10] = '\0';	
			// formato: yyyy/mm/dd<sep>hh:mm:ss.uuuuuu<sep>pid<sep>mensaje
			header << color << strTime << sep;
			strftime(strTime, 20,"%X",timeinfo);
//			strTime[10] = '\0';	
			header << strTime << "." << std::setfill('0') << std::setw(6) << utime.tv_usec << sep << std::setfill(' ') << std::left << std::setw(8) << getpid() << sep;
		}

	public:
//		logger_stream (std::ostream& s, char sep=' ', int color = -1) : sink(s) {
//			this->sep = sep;
//			this->fp = NULL;
//			setColor(color);
//			std::iostream::sync_with_stdio(true);
//		}
		logger_stream (FILE* fp, char sep=' ', const std::string& color = "") {//: sink(std::cerr) {
			this->sep = sep;
			this->fp = fp;
			setColor(color);
			std::iostream::sync_with_stdio(true);
		}

		void PrintHeaderFields() const {
			std::stringstream fields;
			fields << color << std::left << std::setw(10) << "Fecha" << sep << std::setw(15) <<  "Hora" << sep << std::setw(8) << "PID     " << sep << "Mensaje";
			if (!color.empty())
				fields << "\033[0;m";
			fields << '\n';

			if (fp != NULL) {
				const char* str = fields.str().c_str();
				fwrite(str,1,strlen(str),fp);
//			} else {
//				sink << fields.str();
//				sink.flush();
			}
		}

		void setColor(int color) {
			if (color > 0) {
				std::stringstream ss;
				ss << "\033[0;" << color << "m";
				this->color = ss.str();
			} else {
				this->color.clear();
			}
		};
		void setColor(const std::string& color) {
			this->color = color;
		}

		virtual ~logger_stream() {}

		template<typename T>
		logger_stream& operator<< (const T& t) {
			buffer << t;
			return *this;
		}

//		logger_stream& operator<< (const char* str) {
//			buffer.write(str,strlen(str));
//			return *this;
//		}

		logger_stream& operator<<(const multi_line& data) {
			std::ostringstream text;
			std::string header, line;
			
			make_header(text);
			header = text.str() + buffer.str();
			text.str("");
			text.clear();
			buffer.str("");
			buffer.clear();

			while ( std::getline(data.getStream(),line) ) {
				text << header << line;

				if (!color.empty())
					 text << "\033[0;m";
			
				if (!data.getStream().eof())
					text << '\n';
			}
			if (fp != NULL)
				fwrite(text.str().c_str(),1,text.str().length(),fp);

			return *this;
		}

		logger_stream& operator<< (const char c) {
			if (c == '\n') {
				if (buffer.tellp() == 0) {
					fwrite(&c,1,1,fp);
					return *this;
				}

				std::ostringstream line;
				make_header(line);

				if (!color.empty())
					buffer << "\033[0;m";

				line << buffer.str() << '\n';

				if (fp != NULL) {
					fwrite(line.str().c_str(),1,line.str().length(),fp);
//				} else {
//					sink << line.str();
//					sink.flush();
				}
				buffer.str("");
				buffer.clear();
			} else {
				buffer << c;
			}
			return *this;
		}
	
}; // class logger_stream

class no_log {
	public:
		template<typename T>
		inline no_log& operator<< (const T& t) {
			return *this;
		}
}; // class no_log

} // namespace utils

#endif /* __LOGGER_STREAM_HPP__ */

